// ==UserScript==
// @name           Translatorize-for-Facebook
// @namespace      http://translatorize.com/
// @description    Translates user generated content in Facebook
// @author         Micah Wittman
// @include        http://*facebook.com/*
// @include        https://*facebook.com/*
// @version        0.1.3
// ==/UserScript==

/*************************************************************
    Copyright(c) 2009-2010 Micah Wittman
    
    Open Source License:
    Translatorize is licensed under the terms of the
        Open Source GPL 3.0 license.
        http://www.gnu.org/licenses/gpl.html
        
    Licensing inquiries: http://wittman.org/about/

    Translatorize                   http://translatorize.com 
    Translatorize - for Facebook    http://translatorize.com/for/facebook/
    Source Code Project             http://code.google.com/p/translatorize/
    
	Author: Micah Wittman           http://wittman.org
                                    http://facebook.com/Translatorize
                                    http://facebook.com/micah
                                    http://friendfeed.com/Translatorize
                                    
	Versions:
		* 2010-02-16 - version 0.1.3 - Fixed to work with new FB UI (aka The Kevin upgrade).
		  Chat translation support added (also configuration to turn it on/off). Added newly
		  supported languages by Google: Irish.
		* 2009-09-26 - version 0.1.2 - Added newly supported languages by Google: Welsh and Yiddish.
		* 2009-07-30 - version 0.1.1 - Fixed panel hover, setProtocol defined function duplication
		* 2009-07-28 - version 0.1 -   Initial Release.
*************************************************************/

(function(){

	/*************************************************************
	******************** Configuration Begin *********************
	********************                     *********************/
	var scriptnameText = 'Translatorize';
	var translateLinkText = 'Translate X to ENGLISH'; //The text of the translate link.
	var translateReverseLinkText = 'Translate ENGLISH to X'; //The text of the reverse direction translate link.

	/*FOR ALL AVAILABLE GOOGLE TRANSLATION API SUPPORTED LANGUAGES SEE CODES
	HERE:
	http://code.google.com/apis/ajaxlanguage/documentation/reference.html#LangNameArray
	Codes as of 2009-06-24: 'AFRIKAANS':'af', 'ALBANIAN':'sq', 'AMHARIC':'am',
	'ARABIC':'ar', 'ARMENIAN':'hy', 'AZERBAIJANI':'az', 'BASQUE':'eu',
	'BELARUSIAN':'be', 'BENGALI':'bn', 'BIHARI':'bh', 'BULGARIAN':'bg',
	'BURMESE':'my', 'CATALAN':'ca', 'CHEROKEE':'chr', 'CHINESE':'zh',
	'CHINESE_SIMPLIFIED':'zh-CN', 'CHINESE_TRADITIONAL':'zh-TW', 'CROATIAN':'hr',
	'CZECH':'cs', 'DANISH':'da', 'DHIVEHI':'dv', 'DUTCH': 'nl', 'ENGLISH':'en',
	'ESPERANTO':'eo', 'ESTONIAN':'et', 'FILIPINO':'tl', 'FINNISH':'fi',
	'FRENCH':'fr', 'GALICIAN':'gl', 'GEORGIAN':'ka', 'GERMAN':'de', 'GREEK':'el',
	'GUARANI':'gn', 'GUJARATI':'gu', 'HEBREW':'iw', 'HINDI':'hi',
	'HUNGARIAN':'hu', 'ICELANDIC':'is', 'INDONESIAN':'id', 'INUKTITUT':'iu', 'IRISH':'ga',
	'ITALIAN':'it', 'JAPANESE':'ja', 'KANNADA':'kn', 'KAZAKH':'kk', 'KHMER':'km',
	'KOREAN':'ko', 'KURDISH': 'ku', 'KYRGYZ': 'ky', 'LAOTHIAN': 'lo',
	'LATVIAN':'lv', 'LITHUANIAN':'lt', 'MACEDONIAN':'mk', 'MALAY':'ms',
	'MALAYALAM':'ml', 'MALTESE':'mt', 'MARATHI':'mr', 'MONGOLIAN':'mn',
	'NEPALI':'ne', 'NORWEGIAN':'no', 'ORIYA':'or', 'PASHTO':'ps', 'PERSIAN':'fa',
	'POLISH':'pl', 'PORTUGUESE':'pt-PT', 'PUNJABI':'pa', 'ROMANIAN':'ro',
	'RUSSIAN':'ru', 'SANSKRIT':'sa', 'SERBIAN':'sr', 'SINDHI':'sd',
	'SINHALESE':'si', 'SLOVAK':'sk', 'SLOVENIAN':'sl', 'SPANISH':'es',
	'SWAHILI':'sw', 'SWEDISH':'sv', 'TAJIK':'tg', 'TAMIL':'ta', 'TAGALOG':'tl',
	'TELUGU':'te', 'THAI':'th', 'TIBETAN':'bo', 'TURKISH':'tr', 'UKRAINIAN':'uk',
	'URDU':'ur', 'UZBEK':'uz', 'UIGHUR':'ug', 'VIETNAMESE':'vi', 'WELSH':'cy', 'YIDDISH':'yi',
	'UNKNOWN':''*/

	var languageCodeFrom = ''; // Translated FROM - (Empty string '' activates auto-detect, which is the default). Language code as defined by google's translation api - original text. (e.g. '' = auto-detect, 'fa' = Farsi, etc.)
	var languageCodeTo = 'en'; //Translated TO - Language code as defined by google's translation api - translated text (e.g. 'en' = English)

	var translationBackgroundColorFrom = 'rgb(240,240,240)'; //background color of original text (e.g. gray)
	var translationBackgroundColorTo = 'rgb(255,245,175)'; //background color of translated text (e.g. wheat)

	var autoTranslateEnabled = true; //Set to true to automatically translate title/comments when a single entry page is loaded.
	var autoTranslateRealtimeEnabled = true; //Set to true to automatically translate title/comments when a single entry page is loaded.
	var keepOriginalTextInRealtime = true; //Set to true to show the translated text and the original text in a realtime stream. By default it is only shown in single post view.

	var translateTitleOnlyInRealtime = false; //Set to true to only translate an entry title (not comments) in a feed stream.

	var translateChat = true; //Set to true to translate Chat text.

	var autoProtocolMatchingEnabled = true; //Set to true to automatically set all URL references to secure protocol (https) if the current page is https.

	var onlyUseSecureProtocolCompatibleFeatures = true; //Set to true to only use features in script that can utilize a secure connection - https (only applies when the page is using an https connection). Note: currently, this only affects one aspect of this script: that userscripts.org does not support https, so the auto-script update feature will disabled if this is set to true.

	var translateDelay = 2000; //Number of milliseconds by which the realtime feed update is delayed (integer). Set to -1 (negative 1) for an indefinite delay.

	/******************** Configuration End ***********************
	***************************************************************/


	/******************** Pre-Setup Global Variables ************************/
	var protocol = 'http://';
	
	
	/******************** Pre-Setup Functions *******************************/

	function setProtocol()
	{
		if(autoProtocolMatchingEnabled)
		{
			protocol = window.location.protocol + '//';
		}
		if(protocol == 'http://')
		{
			onlyUseSecureProtocolCompatibleFeatures = false; //not a secure connection, so use all features
		}
	}
	setProtocol();


	/******************** Global Variables ************************/
	var version = 'v0.1.3';
	var prevEntryAndCommentCount = null;
	var entries;
	var comments;
	var url = window.location.href;
	var urlPrev = window.location.href;
	var transParagraphCount = 0;
	var linkContent = '<a id="translateLink" href="#" style="color:white;font-weight:bold">' + translateLinkText + '</a>';
	//var linkDiv = ' <span id="translateLinkDiv" style="color:white;font-weight:normal;padding:1px;display:block;">' + linkContent + '</span>';
	var linkDivStyleFlyout = 'cursor:auto;margin:0 0 2px 5px; position:relative; height:250px; min-height:250; background-color:rgb(80,80,80); border-color:darkgray; '
		+ 'color:white; font-weight:normal; padding:4px; display:block;width:175px';
	var linkDivStyle = 'cursor:pointer;margin:2px 0 2px 5px; color:white;font-weight:normal;padding:1px 1px 2px 1px; '
		+'display:block; width:142px;overflow:hidden;height:22px';
	var linkDiv = ' <div id="translateLinkDiv" style="' + linkDivStyle + '">' 
			+ '<div id="facebookTranslateScriptname" style="margin:5px 0 4px 0;border-color:solid 1px gray;">'
			+ scriptnameText + ' Panel ' + ' (<span style="color:white" id="translatorizeTransParagraphCount">' + transParagraphCount + '</span>)'
			+ '</div>'
			+ '<div style="padding:4px 0 0 4px;">'
			+ linkContent
			+ '</div>'
			+ '<br /><br /><table style="border-style:none"><tr><td><div><a href="' + protocol + 'translatorize.com/" title="Translatorize"><img style="vertical-align:middle" id="translatorizePanel" src="' + protocol + 'translatorize.googlecode.com/files/translatorize-panel.png" alt="Translatorize"/></a></div></td>' 
			+ ' <td><div style="margin:5px 16px 0 0;font-size:11px;color:rgb(240,240,240);">' + version + '</div>'
			+ '</div></td></tr></table>'
			+ '<div id="facebookTranslateDonateDiv" height="149" width="100%" style="margin:6px 0 20px 0; padding:4px 0 0 0;">'
			+ '</div>'
		+ '</div>';
	var linkReverseDiv = '<div id="translateReverse" style="padding:4px 0 0 0;"><a id="translateReverseLink" style="color:white;font-weight:bold" href="#"><span>'
		+ translateReverseLinkText + '&nbsp;</span></a></div>';
	var languageCodeFromToUse;
	var languageCodeToToUse;
	var isOneEntry;
	var doAutoTranslate;
	var facebookTranslateSource = 'facebookTranslateSource';


	/****************** Initializing Functions ********************/
	function GM_wait()
	{
	    if(typeof unsafeWindow != 'undefined')
	    {
	        if(typeof unsafeWindow.jQuery != 'undefined')
	        {
				jQuery = unsafeWindow.jQuery;
	        }
	    }
	    if(typeof jQuery == 'undefined')
	    {
			window.setTimeout(GM_wait,251);
	    }
	    else
	    {
			jQuery.noConflict();
			letsJQuery();
	    }
	}

	function letsJQuery()
	{
		setIsOneEntry();
		setDoStartAutoTranslate();

		TranslateLink();
		
		if(doAutoTranslate)
		{
			window.setTimeout(autoTranslate, 2000);
		}
	}



	/************************ Helper Functions ********************/
	function setEntries()
	{
		var chat = translateChat ? ', #chat .chat_conv_content p' : ''; 
		entries = jQuery('.UIIntentionalStory_Message, .UIStoryAttachment_Title, .UIStoryAttachment_Copy, #messages .text, .walltext, .subject_wrap, #notifications .title, .updates_messages [id*=\'essay\'], #info_tab [class*=\'info_\'] dd, #search_results .info dd, .infotable td, .group .group_title, .group .group_description, .profileTable .datawrap, .personal_msg, #gb_content_and_toolbar .GBThreadMessageRow_Body_Content, #contentArea .uiTextTitle, #content .photocaption_text, #content .single_photo_header h2, #contentArea .GenericStory_Message, #contentArea .UIStoryAttachment_Caption, #contentArea .note_content, #content .note_content, #gb_content_and_toolbar .thread_detail > .preview, #gb_content_and_toolbar .thread_detail > .subject' + chat);
		jQuery('#gb_content_and_toolbar .GBThreadRow').css('height','auto'); //make fb-mail list items expandable
	}
	
	function setComments()
	{
		comments = jQuery('.comment_actual_text');
	}

	function setFacebookTranslateSource()
	{
		facebookTranslateSource = 'facebookTranslateSource';
	}
	
	function setFacebookTranslateSourceReverse()
	{
		facebookTranslateSource = 'facebookTranslateSourceReverse';
	}
	
	function loadJquery()
	{
	    var head = document.getElementsByTagName("head")[0];
	    var script = document.createElement("script");
	    var src = protocol + 'ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js';
	    script.setAttribute("language", "javascript");
	    script.setAttribute("src", src);
	    head.appendChild(script);
	}
	
	function google_wait()
	{
	    if(typeof unsafeWindow != 'undefined')
	    {
	        if(typeof unsafeWindow.google != 'undefined')
	        {
				google = unsafeWindow.google;
	        }
	    }
	    if(typeof google == 'undefined')
	    {
			window.setTimeout(google_wait,50);
	    }
	    else
	    {
			googleApiLoad();
	    }
	}

	function requestGoogleScript()
	{
		//Request Script
		var head = document.getElementsByTagName("head")[0];
		var script = document.createElement("script");
	    script.setAttribute("language", "javascript");
	    script.setAttribute("src", protocol + 'www.google.com/jsapi');
	    head.appendChild(script);
	}

	function setTranslationDirectionDefault()
	{
		setFacebookTranslateSource();
		languageCodeFromToUse = languageCodeFrom;
		languageCodeToToUse = languageCodeTo;
	}

	function setTranslationDirectionReverse()
	{
		setFacebookTranslateSourceReverse();
		languageCodeFromToUse = languageCodeTo;
		languageCodeToToUse = languageCodeFrom;
	}

	function googleLoadControllerDefault()
	{
		setTranslationDirectionDefault();
		googleLoadController();
		return false;
	}

	function googleLoadControllerReverse()
	{
		setTranslationDirectionReverse();
		googleLoadController();
	}

	function googleLoadController()
	{

	    if(typeof unsafeWindow != 'undefined')
	    {
	        if(typeof unsafeWindow.google != 'undefined')
	        {
				google = unsafeWindow.google;
	        }
	    }
	    if(typeof google == 'undefined')
	    {
			requestGoogleScript();
			google_wait();
		}
		else
		{
			googleApiLoad();
		}
	}

	function googleApiLoad(){
		google.load('language','1',{"callback":googleApiLoadCallback});
	}

	function googleApiLoadCallback()
	{
		setEntries();
		setComments();
		TranslateProcess();
		Translate_wait();
	}

	function translatedLabelText()
	{
		if(languageCodeFromToUse == languageCodeTo)
		{
			return 'Translated ' + translateReverseLinkText.replace('Translate ',' ') + ' ';
		}
		else
		{
			return  'Translated ' + translateLinkText.replace('Translate ',' ');
		}
	}

	function autoTranslate()
	{
		jQuery('#translateLink').trigger('click');
	}

	function doTranslation(result)
	{
		var doTran = false;
		if(languageCodeFromToUse != '')
		{
			doTran = true;
		}
		else
		{
			if(typeof result != 'undefined')
			{
				if(typeof result.detectedSourceLanguage != 'undefined')
				{
					if(result.detectedSourceLanguage != languageCodeTo)
					{
						doTran = true;
					}
				}
			}
		}
		return doTran;
	}
	
	function Translate_wait()
	{
		setEntries();
		setComments();
		var entryAndCommentCount = entries.length + comments.length + jQuery('.facebookTranslate').length;
	    var translateDelayToUse = translateDelay;

	    if(translateDelay < 0)
	    {
	        translateDelayToUse = 2000;
	    }
		if(entryAndCommentCount == prevEntryAndCommentCount)
		{
			window.setTimeout(Translate_wait, translateDelayToUse);
		}
		else
		{
			prevEntryAndCommentCount = entryAndCommentCount;
			if(translateDelay >= 0)
			{
				TranslateProcess();
				Translate_wait();
			}
		}

	}
	
	function setIsOneEntry()
	{
		return true; //not applicable in fb
	}

	function setDoStartAutoTranslate()
	{
		doAutoTranslate = doStartAutoTranslate();
	}

	function doStartAutoTranslate()
	{
		var doStartAutoTrans = false;
		if(isOneEntry)
		{
			//One Entry
			if(autoTranslateEnabled)
			{
				doStartAutoTrans = true;
			}
		}
		else
		{
			//Stream
			if(autoTranslateRealtimeEnabled)
			{
				doStartAutoTrans = true;
			}
		}
		return doStartAutoTrans;
	}

	function titleIsOnlyUsername(title)
	{
		if( jQuery.trim(title.find('.UIIntentionalStory_Names').text()) == jQuery.trim(title.text()) )
		{
			return true;
		}
		else
		{
			return false;
		}
	}

	function preTranslateHtmlScrub(html)
	{
		return html.replace(/<img[^>]+>/g,' ');
	}



	/***************** Main Processing Functions ******************/
	function TranslateLink()
	{
		if(jQuery('#translateLink, translateLinkDiv').length == 0)
		{
			var donateLinkHtml = '<a href="' + protocol + 'pledgie.com/campaigns/5387"><img height="37" width="149" alt="Click here to lend your support to: Translatorize and make a donation at www.pledgie.com !" src="' + protocol + 'pledgie.com/campaigns/5387.png?skin_name=chrome" border="0" /></a>';
			//jQuery('li.fbm_last:last').append(linkDiv);
			jQuery('ul#pageNav > li:last').after('<li>' + linkDiv + '</li>');
			jQuery('#translateLink').click(googleLoadControllerDefault);
			jQuery('.updates_messages [id*=\'essay-summary\'] a').click(googleLoadControllerDefault);
			jQuery('#translateLinkDiv')
				.hover(function(){
					if(jQuery(this).css('opacity') == '1')
					{
						var facebookTranslateDonateDiv = jQuery('#facebookTranslateDonateDiv');
						if(facebookTranslateDonateDiv.children().length == 0)
						{
							facebookTranslateDonateDiv.append(donateLinkHtml);
						}
						jQuery(this).hide().fadeIn(50, function(){
							jQuery(this).attr('style', linkDivStyleFlyout); //On hover over
						});
					}
	         	}, function(){  //On hover out  
					jQuery(this).fadeOut(600, function(){
						jQuery(this).attr('style', linkDivStyle);
						jQuery(this).removeClass('tranlatorizePanelMax');
					})
					.show()
					.click(function(){
						if(!jQuery(this).hasClass('tranlatorizePanelMax'))
						{
							jQuery(this).addClass('tranlatorizePanelMax');
							var facebookTranslateDonateDiv = jQuery('#facebookTranslateDonateDiv');
							if(facebookTranslateDonateDiv.children().length == 0)
							{
								facebookTranslateDonateDiv.append(donateLinkHtml);
							}
							jQuery(this).hide().fadeIn(50, function(){
								jQuery(this).attr('style', linkDivStyleFlyout); //On hover over
							});
						}
				});
			});
		}
	}

	function TranslateProcess()
	{
		var afterClickLinkContent = '<div id="translateAfter" style="padding:2px 0 2px 0;color:rgb(255,225,10);font-weight:bold">&nbsp;' + '&gt;&gt; Processed &lt;&lt;' + '&nbsp; <span id="translateUndo"><a style="color:white;font-size:10px" href="#" onclick="window.location.reload(false); return false;">Undo</a></span></div>';
		var titles = entries;
		var titleOnlyUsername = false;
		var titleHtml;
		var insertHtml;
		var shouldTranslate = true;
	
		titles.each(function(){
		
			var title = jQuery(this);  
			var titleOnlyUsername = titleIsOnlyUsername(title);
			if(!title.hasClass(facebookTranslateSource) && !titleOnlyUsername && title.css('display') != 'none')
			{
				if(title.css('display') != 'none')
				{
					title.addClass(facebookTranslateSource);
				}
				titleHtml = preTranslateHtmlScrub(title.html()); 
				google.language.translate(titleHtml, languageCodeFromToUse, languageCodeToToUse, function(result){
					if(doTranslation(result))
					{
						if(result.translation) {
							insertHtml = '<div class="facebookTranslate" style="width:393px;margin:4px 0 4px 0;padding:2px 4px 2px 4px;background-color:' + translationBackgroundColorTo + '">' + result.translation + '</div>';
						
							shouldTranslate = true;
							if(title.hasClass('label') && title[0].tagName == 'TD')
							{
								shouldTranslate = false;
							}
						
							if(shouldTranslate)
							{
								transParagraphCount++;
								if(title[0].tagName == 'DD' || title[0].tagName == 'TD')
								{
									title.append(insertHtml); //is an info tab <dd>, so append, not insert after.
								}
								else
								{
									title.after(insertHtml);
								}
								if(!isOneEntry && !keepOriginalTextInRealtime)
								{
									title.hide();
								}
							}
						}
					}
				
				});
			}
		});
	
		//Translate comments
		if(!isOneEntry && !translateTitleOnlyInRealtime)
		{
			comments.each(function(){
				var comm = jQuery(this);
				var commHtml = preTranslateHtmlScrub(comm.html());
				if(!comm.hasClass(facebookTranslateSource))
				{
					comm.addClass(facebookTranslateSource);
					google.language.translate(commHtml, languageCodeFromToUse, languageCodeToToUse, function(result){
						if(doTranslation(result))
						{
							comm.css('padding','10px 4px 4px 4px');
							if(result.translation)
							{
								transParagraphCount++;
								comm.after('<div class="facebookTranslate" style="background-color:' + translationBackgroundColorTo + ' !important;padding:1px 4px 10px 4px;margin:4px 2px 4px 2px; border-bottom:1px gray solid;">' + result.translation + '</div>');	
								if(!isOneEntry && !keepOriginalTextInRealtime)
								{
									comm.hide();
								}
							}
						}
				
					});
				}
			});
		}
		jQuery('#translatorizeTransParagraphCount').empty().append(transParagraphCount);
		jQuery('#translateAfter').remove();
		jQuery('#translateUndo').remove();

		jQuery('#facebookTranslateScriptname').after(afterClickLinkContent);
	
		jQuery('#translateReverse').remove();
		if(languageCodeFrom != '')
		{
			jQuery('#translateLink').after(linkReverseDiv);		
			jQuery('#translateReverseLink').click(googleLoadControllerReverse);
		}
		return false;
	}


	/*************************************************************
	************************** RUN SCRIPT ************************
	********************                     *********************/
	if(window.location.href.indexOf('facebook.com/') > -1) //greasekit doesn't support @include directs, so test URL for context
	{
		if(typeof jQuery == 'undefined')
		{
			loadJquery();
		}
		GM_wait();
	}

})();